Skip to content

fix(postgresql,kingbase): quote foreign schema and table in REFERENCES - #2187

Closed
Aias00 wants to merge 1 commit into
OtterMind:mainfrom
Aias00:fix/2184-pg-kingbase-fk-quote
Closed

fix(postgresql,kingbase): quote foreign schema and table in REFERENCES#2187
Aias00 wants to merge 1 commit into
OtterMind:mainfrom
Aias00:fix/2184-pg-kingbase-fk-quote

Conversation

@Aias00

@Aias00 Aias00 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Related issue

Closes #2184

Summary

PostgreSQLIndexTypeEnum.buildForeignColum (and the identical KingBaseIndexTypeEnum) concatenated getForeignSchemaName() and getForeignTableName() raw into the REFERENCES clause, while the foreign columns below were double-quoted. PostgreSQL/KingBase fold unquoted identifiers to lowercase, so a foreign table with an uppercase/mixed-case name produced a REFERENCES clause pointing at a non-existent relation. Wrapped both in double-quotes, matching the column quoting in the same method. Applied to both PostgreSQL and KingBase.

Verification

  • mvn compile -> BUILD SUCCESS.

Contributor declaration

  • I linked the Issue that defines this change.
  • I tested the affected behavior and reported the actual results above.
  • I did not include credentials, private data, or generated build output.
  • I disclosed substantial AI assistance below, or this PR contains no substantial AI-generated code.

AI assistance: The fix, verification, and PR description were produced with Claude Code assistance.

The foreign schema and table were concatenated raw while the foreign
columns below were double-quoted. PostgreSQL/KingBase fold unquoted
identifiers to lowercase, so mixed-case foreign table names produced a
REFERENCES clause pointing at a non-existent relation. Wrap in
double-quotes, matching the column quoting in the same method.

Fixes OtterMind#2184

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 26, 2026 15:08
@Aias00
Aias00 requested a review from openai0229 as a code owner July 26, 2026 15:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Aias00

Aias00 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Live-database verification (PostgreSQL 16)

  • Quoted FK: REFERENCES "TestSchema"."TestTable" ("anotherCol") → ✅ CREATE TABLE
  • Unquoted table: REFERENCES "TestSchema".TestTable ("anotherCol") → ❌ ERROR: relation "TestSchema.testtable" does not exist

The foreign columns were already double-quoted in the same method; this fix quotes the schema and table to match.

@openai0229

Copy link
Copy Markdown
Contributor

Thanks for the live PostgreSQL verification. It confirms why the mixed-case referenced object cannot be resolved when it is left unquoted, but directly concatenating " around schema/table names at the call site is not the right abstraction.

Please pass the raw schema, table, and column identifier components to ISQLIdentifierProcessor, and let the dialect-specific processor return the complete SQL identifier token. Callers should not pre-quote identifiers, and each component of a qualified name should be processed separately before joining them with ..

Could you please rework this PR, as well as the other similar quote-related PRs, in that direction? If the current processor API cannot express an explicit always-quote/preserve-exact-name operation, please extend the shared SPI first instead of adding direct delimiters or plugin-local helpers. The shared contract also needs to escape embedded delimiter characters correctly and satisfy removeQuote(quoteIdentifierAlways(raw)) == raw.

Please add automated tests rather than relying only on the manual PostgreSQL check. At minimum, cover:

  • conditional and always-quote behavior;
  • embedded delimiters such as A"B;
  • reserved words and dialect-specific case folding;
  • qualified schema/table/column identifiers;
  • generated REFERENCES DDL, including execution against the target database where practical.

It would be better to make this shared processor contract and its tests complete first, then rebase the individual dialect PRs onto it.

@Aias00

Aias00 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Created the foundational SPI extension PR: #2234

It adds quoteIdentifierAlways(String) to ISQLIdentifierProcessor with proper delimiter escaping (double-quote, backtick, bracket variants), fixes removeIdentifierQuote to unescape doubled delimiters (satisfying the round-trip contract), and includes 36 tests covering conditional vs always-quote, embedded delimiters, reserved keywords, case preservation, and round-trip behavior across Default, MySQL, and SqlServer processors.

Once #2234 merges, I'll rework this PR and the other quoting PRs (#2145, #2169, #2185, #2186) to use processor.quoteIdentifierAlways(name) instead of direct " concatenation.

@Aias00

Aias00 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of #2264 which uses the SPI quoteIdentifierAlways method per the maintainer review.

@Aias00 Aias00 closed this Jul 27, 2026
@openai0229 openai0229 moved this from In Review to Done in Chat2DB Community Jul 27, 2026
Aias00 added a commit to Aias00/Chat2DB that referenced this pull request Jul 27, 2026
…chema and table in REFERENCES

Replaces direct " concatenation with the dialect-specific processor:
PostgreSQLMetaData.POSTGRE_SQL_IDENTIFIER_PROCESSOR and
KingBaseMetaData.KINGBASE_SQL_IDENTIFIER_PROCESSOR.
Built on the SPI extension (OtterMind#2234).

Closes OtterMind#2187 (superseded by this SPI-based approach)

Co-Authored-By: Claude <noreply@anthropic.com>
@Aias00

Aias00 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Correction: #2187 is closed in favor of #2265 (not #2264) which uses the SPI quoteIdentifierAlways method.

Aias00 added a commit to Aias00/Chat2DB that referenced this pull request Jul 27, 2026
Add a new SPI method that unconditionally quotes an identifier,
preserving the exact name regardless of case or keyword status.
Embedded delimiter characters are escaped per the dialect convention
(double-quote "" for ", backtick `` for `, bracket ]] for ]).

Fix removeIdentifierQuote to unescape doubled delimiters, satisfying
the round-trip contract: removeIdentifierQuote(quoteIdentifierAlways(raw)).equals(raw).

Implementations:
- DefaultSQLIdentifierProcessor: double-quote + escape " -> ""
- MysqlIdentifierProcessor: backtick + escape ` -> ``
- SqlServerIdentifierProcessor: bracket + escape ] -> ]]

Also add SNOWFLAKE_SQL_IDENTIFIER_PROCESSOR static field to
SnowflakeMetaData, mirroring PostgreSQL/KingBase, to give Snowflake
column-type enums access to the processor for downstream quoting PRs.

Tests: 36 tests covering conditional vs always-quote, embedded
delimiters, round-trip, reserved keywords, and case preservation
across Default, MySQL, and SqlServer processors.

Addresses the maintainer review on OtterMind#2187 requesting the shared SPI
contract be extended before rebasing the individual dialect quoting PRs.

Co-Authored-By: Claude <noreply@anthropic.com>
Aias00 added a commit to Aias00/Chat2DB that referenced this pull request Jul 27, 2026
Replaces direct backtick concatenation with
KingBaseMetaData.KINGBASE_SQL_IDENTIFIER_PROCESSOR.quoteIdentifierAlways,
per the maintainer review on OtterMind#2187. Built on the SPI extension (OtterMind#2234).

Closes OtterMind#2145 (superseded by this SPI-based approach)

Co-Authored-By: Claude <noreply@anthropic.com>
Aias00 added a commit to Aias00/Chat2DB that referenced this pull request Jul 27, 2026
…chema and table in REFERENCES

Replaces direct " concatenation with the dialect-specific processor:
PostgreSQLMetaData.POSTGRE_SQL_IDENTIFIER_PROCESSOR and
KingBaseMetaData.KINGBASE_SQL_IDENTIFIER_PROCESSOR.
Built on the SPI extension (OtterMind#2234).

Closes OtterMind#2187 (superseded by this SPI-based approach)

Co-Authored-By: Claude <noreply@anthropic.com>
Aias00 added a commit to Aias00/Chat2DB that referenced this pull request Jul 28, 2026
Add a new SPI method that unconditionally quotes an identifier,
preserving the exact name regardless of case or keyword status.
Embedded delimiter characters are escaped per the dialect convention
(double-quote "" for ", backtick `` for `, bracket ]] for ]).

Fix removeIdentifierQuote to unescape doubled delimiters, satisfying
the round-trip contract: removeIdentifierQuote(quoteIdentifierAlways(raw)).equals(raw).

Implementations:
- DefaultSQLIdentifierProcessor: double-quote + escape " -> ""
- MysqlIdentifierProcessor: backtick + escape ` -> ``
- SqlServerIdentifierProcessor: bracket + escape ] -> ]]

Also add SNOWFLAKE_SQL_IDENTIFIER_PROCESSOR static field to
SnowflakeMetaData, mirroring PostgreSQL/KingBase, to give Snowflake
column-type enums access to the processor for downstream quoting PRs.

Tests: 36 tests covering conditional vs always-quote, embedded
delimiters, round-trip, reserved keywords, and case preservation
across Default, MySQL, and SqlServer processors.

Addresses the maintainer review on OtterMind#2187 requesting the shared SPI
contract be extended before rebasing the individual dialect quoting PRs.

Co-Authored-By: Claude <noreply@anthropic.com>
openai0229 pushed a commit to Aias00/Chat2DB that referenced this pull request Jul 29, 2026
Add a new SPI method that unconditionally quotes an identifier,
preserving the exact name regardless of case or keyword status.
Embedded delimiter characters are escaped per the dialect convention
(double-quote "" for ", backtick `` for `, bracket ]] for ]).

Fix removeIdentifierQuote to unescape doubled delimiters, satisfying
the round-trip contract: removeIdentifierQuote(quoteIdentifierAlways(raw)).equals(raw).

Implementations:
- DefaultSQLIdentifierProcessor: double-quote + escape " -> ""
- MysqlIdentifierProcessor: backtick + escape ` -> ``
- SqlServerIdentifierProcessor: bracket + escape ] -> ]]

Also add SNOWFLAKE_SQL_IDENTIFIER_PROCESSOR static field to
SnowflakeMetaData, mirroring PostgreSQL/KingBase, to give Snowflake
column-type enums access to the processor for downstream quoting PRs.

Tests: 36 tests covering conditional vs always-quote, embedded
delimiters, round-trip, reserved keywords, and case preservation
across Default, MySQL, and SqlServer processors.

Addresses the maintainer review on OtterMind#2187 requesting the shared SPI
contract be extended before rebasing the individual dialect quoting PRs.

Co-Authored-By: Claude <noreply@anthropic.com>
openai0229 added a commit that referenced this pull request Jul 29, 2026
* feat(spi): add quoteIdentifierAlways to ISQLIdentifierProcessor

Add a new SPI method that unconditionally quotes an identifier,
preserving the exact name regardless of case or keyword status.
Embedded delimiter characters are escaped per the dialect convention
(double-quote "" for ", backtick `` for `, bracket ]] for ]).

Fix removeIdentifierQuote to unescape doubled delimiters, satisfying
the round-trip contract: removeIdentifierQuote(quoteIdentifierAlways(raw)).equals(raw).

Implementations:
- DefaultSQLIdentifierProcessor: double-quote + escape " -> ""
- MysqlIdentifierProcessor: backtick + escape ` -> ``
- SqlServerIdentifierProcessor: bracket + escape ] -> ]]

Also add SNOWFLAKE_SQL_IDENTIFIER_PROCESSOR static field to
SnowflakeMetaData, mirroring PostgreSQL/KingBase, to give Snowflake
column-type enums access to the processor for downstream quoting PRs.

Tests: 36 tests covering conditional vs always-quote, embedded
delimiters, round-trip, reserved keywords, and case preservation
across Default, MySQL, and SqlServer processors.

Addresses the maintainer review on #2187 requesting the shared SPI
contract be extended before rebasing the individual dialect quoting PRs.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spi): enforce identifier quoting contract

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: zgq <openai0229@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

PostgreSQL/KingBase foreign-key REFERENCES leaves schema and table unquoted

3 participants